#include <stdio.h>
#include <unistd.h>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include "sound.h"
#include "system.h"

// Callbacks
void* preload(void* object) {
	((System*)object)->preloaderThread();
	pthread_exit(NULL);
	return NULL;
}

// Class members
System::System(Sync* sync) {
	this->sync = sync;
	this->sound = new Sound(sync);
	this->preloadDone = false;
}

System::~System() {
	delete sound;

	// free the components
	std::map<int,Component*>::iterator iterator = components.begin();
	while (iterator != components.end()) {
		delete (*iterator).second;
		iterator++;
	}
}

void
System::registerComponent(int id, Component* component) {
	components[id] = component;
	printf("Register component #%d\n", id);
}

void
System::activate(int id, Interval interval) {
	activation.insert(std::pair<int, Interval>(id, interval));
	printf("#%d: interval %f->%f\n", id, interval.from, interval.to);
}

void
System::run(float dt) {
	float time = sync->time();
	if (preloadDone) {
		// main demo code

		// run all active components
		std::multimap<int, Interval>::iterator it = activation.begin();
		while (it != activation.end()) {
			Interval interval = (*it).second;
			if (interval.contains(time) || interval < time) {
				// run component
				int id = (*it).first;
				components[id]->draw(time - interval.from, dt, interval.alpha(time));
			}

			// remove passed intervals
			std::multimap<int, Interval>::iterator current = it++;
			if (interval < time) {
				activation.erase(current);
			}
		}
	} else {
		// TODO: preloader
	}
}

void
System::start() {
	startPreloader();
}

void
System::stop() {
	sound->stop();
}

void
System::startPreloader() {
	preloadDone = false;

	/*
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	pthread_create(&preloadThread, &attr, preload, (void *)this);
	pthread_attr_destroy(&attr);
	*/

	this->preloaderThread();
}


void
System::preloaderThread() {
	std::map<int,Component*>::iterator iterator = components.begin();
	while (iterator != components.end()) {
		(*iterator).second->initialize();
		iterator++;
	}
	sound->initialize();
	preloadDone = true;
	sound->start();
}


Interval::Interval(const float from, const float to) {
	this->from = from;
	this->to = to;
}

bool
Interval::contains(const float t) {
	if (to == UNBOUND) return from <= t;
	return from <= t && t <= to;
}

float
Interval::alpha(const float t) {
	if (to == UNBOUND) return 1;
	if (t <= from) return 0;
	if (t >= to) return 1;
	return (t-from)/(to-from);
}

bool operator< (const Interval& a, const float t) {
	if (a.to == UNBOUND) return false;
	return a.to < t;
}

bool operator< (const Interval& a, const Interval &b) {
	if (a.from == UNBOUND && b.from == UNBOUND)
		return a.to < b.to;
	if (a.from == UNBOUND) return true;
	if (b.from == UNBOUND) return false;
	return a.from < b.from;
}

bool operator> (const Interval& a, const Interval &b) {
	if (a.to == UNBOUND && b.to == UNBOUND)
		return a.from > b.from;
	if (a.to == UNBOUND) return true;
	if (b.to == UNBOUND) return false;
	return a.to > b.to;
}
